#include <iostream>
#include <string>
#include <unistd.h>
#include <cstdlib>
#include <vector>
#include "task.hpp"
#include <ctime>
#include <sys/wait.h>
using namespace std;

enum
{
    UsageError = 1,
    ArgError,
    PipeError
};

void Usage(const std::string &proc)
{
    cout << "Usage: " << proc << "subprocess-num" << endl;
}

class Channel
{
public:
    Channel(int wfd, pid_t sub_id, const std::string &name)
        : _wfd(wfd),
          _sub_process_id(sub_id),
          _name(name)
    {
    }

    string name() { return _name; }
    int wfd() { return _wfd; }
    pid_t pid() { return _sub_process_id; }
    ~Channel()
    {
    }

    void PrintfDebug()
    {
        cout << "_wfd:" << _wfd;
        cout << " _sub_process:" << _sub_process_id;
        cout << " _name:" << _name << endl;
    }

    void Close(){close(_wfd);}
private:
    int _wfd;
    pid_t _sub_process_id;
    string _name;
};

class ProcessPool
{
public:
    ProcessPool(int sub_process_num) : _sub_process_num(sub_process_num) {}

    int CreatePeocess(work_t work) // 使用回调函数
    {
        for (int number = 0; number < _sub_process_num; number++)
        {
            int pipefd[2]{0};     // 接收管道描述符,初始化为0
            int n = pipe(pipefd); // 创建管道pipe，将读写端赋值，返回创建情况
            if (n < 0)
                return PipeError;

            pid_t id = fork(); // 创建子进程
            if (id == 0)
            {
                // 子进程 "r"
                close(pipefd[1]);

                // 工作任务
                dup2(pipefd[0], 0);
                work();
                exit(0);
            }

            string cname = "channel-" + to_string(number); // 给每个子进程取名

            // 父进程
            close(pipefd[0]);
            channels.push_back(Channel(pipefd[1], id, cname)); // 将进程封装成channel对象，使用vector管理
        }
        return 0;
    }

    int NextChanel()
    {
        static int next = 0;
        int c = next++;
        next %= channels.size();
        return c;
    }

    void SendTaskCode(int index, uint32_t code)
    {
        cout << "发送任务码：" << code << "给" << channels[index].name() << "当前进程id：" << channels[index].pid() << endl;
        write(channels[index].wfd(), &code, sizeof(code));
    }

    void KillAll()  //关闭所有的写端即可关闭所有的读端
    {
        for(auto &channel : channels)
        {
            channel.Close();
            cout<<channel.name()<<"当前进程已退出"<<endl;
        }
    }

    void Wait()
    {
        for (auto &channel : channels)
        {
            pid_t pid = channel.pid();
            pid_t rid = waitpid(pid,nullptr,0);   
            if(rid == pid)
            {
                cout<< "回收进程："<< pid << "成功"<<endl; 
            }
        }

    }

    void DeBug()
    {
        for (auto &channel : channels)
        {
            channel.PrintfDebug();
        }
    }
    ~ProcessPool()
    {
    }

private:
    int _sub_process_num;
    vector<Channel> channels;
};

int main(int argc, char *argv[])
{
    // 命令行检测
    if (argc != 2)
    {
        Usage(argv[0]);
        return UsageError;
    }

    int sub_process_num = std::stoi(argv[1]);
    if (sub_process_num <= 0)
        return ArgError;

    srand((uint64_t)time(nullptr));

    // 1.创建管道和子进程
    ProcessPool *processpool_ptr = new ProcessPool(sub_process_num);
    processpool_ptr->CreatePeocess(worker);
    // processpool_ptr->DeBug();

    // 2.控制子进程
    while(true)
    {
        // a.选择一个进程和通道
        int channel = processpool_ptr->NextChanel();
        // cout << channel.name()<<endl;

        // b.选择一个任务
        uint32_t code = NextTask();

        // c.发送任务
        processpool_ptr->SendTaskCode(channel, code); 
        sleep(1);
    }

    // 3.回收子进程
        //a.退出所有子进程
        processpool_ptr->KillAll();
        //b.回收子进程资源
        processpool_ptr->Wait();
    delete processpool_ptr;

    return 0;
}